param(
    [string]$QemuPath = "qemu-system-riscv64",
    [switch]$Gdb,
    [int]$GdbPort = 26000,
    [switch]$Net,
    [int]$ForwardPort = 26999,
    [int]$Cpus = 3
)

$ErrorActionPreference = "Stop"
Set-StrictMode -Version Latest

$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$repoRoot = Split-Path -Parent $scriptDir

$kernelPath = Join-Path $repoRoot "kernel\kernel"
$fsImagePath = Join-Path $repoRoot "fs.img"

function Resolve-QemuExecutable {
    param(
        [Parameter(Mandatory)]
        [string]$Candidate
    )

    $isPath = $Candidate.Contains('\') -or $Candidate.Contains('/')

    if ($isPath -and (Test-Path $Candidate)) {
        return (Resolve-Path $Candidate).ProviderPath
    }

    $envHome = $env:QEMU_HOME
    if ($isPath -and -not (Test-Path $Candidate)) {
        throw "QEMU executable '$Candidate' not found."
    }

    $extensions = @("", ".exe", ".cmd", ".bat")
    $searchNames = @($Candidate)
    if ($envHome) {
        foreach ($ext in $extensions) {
            $searchNames += Join-Path $envHome ("qemu-system-riscv64" + $ext)
        }
    }

    foreach ($name in $searchNames) {
        foreach ($ext in $extensions) {
            $probe = $name
            if (-not $probe.EndsWith($ext, [System.StringComparison]::OrdinalIgnoreCase)) {
                $probe = "$name$ext"
            }
            try {
                $command = Get-Command $probe -ErrorAction Stop
                if ($command.CommandType -in "Application","ExternalScript") {
                    return $command.Source
                }
            } catch {
                continue
            }
            if (Test-Path $probe) {
                return (Resolve-Path $probe).ProviderPath
            }
        }
    }

    throw "Unable to locate QEMU executable. Add it to PATH, set QEMU_HOME, or pass -QemuPath with a full path."
}

if (-not (Test-Path $kernelPath)) {
    throw "Missing kernel binary at $kernelPath. Build xv6 inside Linux/WSL first (e.g. `make qemu`), then rerun this script."
}

if (-not (Test-Path $fsImagePath)) {
    throw "Missing file system image at $fsImagePath. Build it inside Linux/WSL first."
}

$qemuArgs = @(
    "-machine", "virt",
    "-bios", "none",
    "-kernel", $kernelPath,
    "-m", "128M",
    "-smp", $Cpus,
    "-nographic",
    "-global", "virtio-mmio.force-legacy=false",
    "-drive", "file=$fsImagePath,if=none,format=raw,id=x0",
    "-device", "virtio-blk-device,drive=x0,bus=virtio-mmio-bus.0"
)

if ($Net.IsPresent) {
    $netArgs = @(
        "-netdev", "user,id=net0,hostfwd=udp::$ForwardPort-:2000",
        "-object", "filter-dump,id=net0,netdev=net0,file=packets.pcap",
        "-device", "e1000,netdev=net0,bus=pcie.0"
    )
    $qemuArgs += $netArgs
}

if ($Gdb.IsPresent) {
    $qemuArgs += @("-S", "-gdb", "tcp::$GdbPort")
}

$resolvedQemu = Resolve-QemuExecutable -Candidate $QemuPath

Write-Host "Launching $resolvedQemu with arguments:"
Write-Host "  $($qemuArgs -join ' ')"

$process = Start-Process -FilePath $resolvedQemu -ArgumentList $qemuArgs -NoNewWindow -PassThru
$process.WaitForExit()
exit $process.ExitCode
